#include "teststdafx.h"
#include "stdafx.h"
#include <gtest/gtest.h>

#include "Business/Policy/OneLegArbitrageBusiness.h"
#include "Utils/FastBlockQueue.h"
#include "Business/QueueContext.h"
#include "Repository/CancellationRepository.h"
#include "Repository/DealingRepository.h"
#include "Service/MarketStorage.h"
#include "Business/Customer.h"
#include "Business/Command.h"

using namespace std;

class OneLegArbitrageBusinessTest : public testing::Test
{
protected:

	virtual void SetUp()
	{
		HANDLE hQuit = ::CreateEvent(NULL,TRUE,FALSE,NULL);
		m_customer.reset(new Customer("","",""));
		m_customer->SetOrginalAmount(100000.00);
		m_requestQueue.reset(FastBlockQueue::Create(hQuit));
		m_businessQueue.reset(FastBlockQueue::Create(hQuit));
		m_uiQueue.reset(FastBlockQueue::Create(hQuit));
		m_highTimerQueue.reset(FastBlockQueue::Create(hQuit));
		m_waitTimerQueue.reset(FastBlockQueue::Create(hQuit));
		m_dealingRepository.reset(new DealingRepository());
		m_cancellationRepository.reset(new CancellationRepository());
		m_queueContext.reset(new QueueContext(*m_requestQueue,*m_businessQueue,*m_uiQueue,*m_highTimerQueue,*m_waitTimerQueue));

		InitMarket();

		m_business.reset(new OneLegArbitrageBusiness(*m_customer,OneLegArbitrageArguemnt(ArbitrageContracts(0,1),4,2000,3),
			m_marketStorage,*m_queueContext,*m_dealingRepository,*m_cancellationRepository));

	}
	virtual void TearDown()
	{
	}
	void InitMarket()
	{
		Margins margins;
		margins.Add(Margin("",0.1));
		{
			Variety variety("zn1010",10,5);
			variety.SetMargins(margins);
			double lastPrice = 3000.00;
			Prices buyPrices;
			buyPrices[0] = Price(3010,10);
			Prices sellPrices;
			sellPrices[0] = Price(2990,5);
			double upperLimit = 4000.00;
			double lowerLimit = 2000.00;
			double preSettlementPrice  = 3100.00;
			Market market(0,variety,lastPrice,0,buyPrices,sellPrices,upperLimit,lowerLimit,preSettlementPrice); 

			m_marketStorage.Save(market);
		}
		{
			Variety variety("rb1011",10,5);
			variety.SetMargins(margins);
			double lastPrice = 3000.00;
			Prices buyPrices;
			buyPrices[0] = Price(3010,10);
			Prices sellPrices;
			sellPrices[0] = Price(2990,5);
			double upperLimit = 4000.00;
			double lowerLimit = 2000.00;
			double preSettlementPrice  = 3100.00;
			Market market(1,variety,lastPrice,0,buyPrices,sellPrices,upperLimit,lowerLimit,preSettlementPrice); 

			m_marketStorage.Save(market);

		}
	}

	Market CreateMarket0()
	{
		Variety variety("UNDEFINED",-1,-1);
		double lastPrice = 3000.00;
		Prices buyPrices;
		buyPrices[0] = Price(3010,10);
		Prices sellPrices;
		sellPrices[0] = Price(2990,5);
		double upperLimit = 4000.00;
		double lowerLimit = 2000.00;
		double preSettlementPrice  = 3100.00;
		return Market(0,variety,lastPrice,0,buyPrices,sellPrices,upperLimit,lowerLimit,preSettlementPrice); 
	}

	MarketStorage m_marketStorage;
	auto_ptr<FastBlockQueue> m_requestQueue;
	auto_ptr<FastBlockQueue> m_businessQueue;
	auto_ptr<FastBlockQueue> m_uiQueue;
	auto_ptr<FastBlockQueue> m_highTimerQueue;
	auto_ptr<FastBlockQueue> m_waitTimerQueue;
	auto_ptr<Customer> m_customer;
	auto_ptr<OneLegArbitrageBusiness> m_business;
	auto_ptr<DealingRepository> m_dealingRepository;
	auto_ptr<CancellationRepository> m_cancellationRepository;
	auto_ptr<QueueContext> m_queueContext;

	void foo();

	void ExpectSnapshot(char const* statusName, Direction::TYPE direction, int minorQuantity)
	{
		EXPECT_EQ(1,m_queueContext->GetUIQueue().Size());
		bool quitFlag = false;
		QueueItem const& item = m_queueContext->GetUIQueue().Pop(quitFlag);
		EXPECT_EQ(QueueItem::COMMAND,item.type);
		Command const& cmd = *(Command*)item.data;
		EXPECT_EQ(Command::UI_UPDATE_BUSINESS_INFO,cmd.type);
		OneLegArbitrageBusinessSnapshot const& snapshot = *(OneLegArbitrageBusinessSnapshot*)cmd.data;
		EXPECT_STREQ(statusName,snapshot.GetStatus());
		EXPECT_EQ(direction,snapshot.GetDirection());
		EXPECT_EQ(minorQuantity,snapshot.GetMinorQuantity());
	}

	void ExpectOrder(int contract,Operation::TYPE operation,Direction::TYPE direction, int quantity,double price)
	{
		EXPECT_EQ(1,m_queueContext->GetRequestQueue().Size());
		bool quitFlag = false;
		QueueItem const& item = m_queueContext->GetRequestQueue().Pop(quitFlag);
		EXPECT_EQ(QueueItem::ORDER,item.type);
		Dealing const& dealing = *(Dealing*)item.data;
		EXPECT_EQ(contract,dealing.GetContract());
		EXPECT_EQ(operation,dealing.GetOperation());
		EXPECT_EQ(direction,dealing.GetDirection());
		EXPECT_EQ(quantity,dealing.GetOrderQuantity());
		EXPECT_EQ(price,dealing.GetOrderPrice());
	}

	void ExpectCancellation(int localId)
	{
		EXPECT_EQ(1,m_queueContext->GetRequestQueue().Size());
		bool quitFlag = false;
		QueueItem const& item = m_queueContext->GetRequestQueue().Pop(quitFlag);
		EXPECT_EQ(QueueItem::CANCELLATION,item.type);
		Cancellation const& cancellation = *(Cancellation*)item.data;
		EXPECT_EQ(localId,cancellation.GetOrderLocalId());
	}

	void OnCommand(Command::TYPE type)
	{
		Command cmd = {0};
		cmd.type = type;
		cmd.business = m_business.get();
		m_business->OnCommand(cmd);
	}

	Dealing* OnOrdered()
	{
		bool quitFlag = false;
		QueueItem const& item = m_queueContext->GetRequestQueue().Pop(quitFlag);
		Dealing* dealing = m_dealingRepository->Get(((Dealing*)item.data)->GetLocalId());
		dealing->OnOrdered(FT("%d",dealing->GetLocalId()));
		m_business->OnDealing(*dealing);
		return dealing;
	}

	Dealing* OnCancellationSuccess()
	{
		bool quitFlag = false;
		QueueItem const& item = m_queueContext->GetRequestQueue().Pop(quitFlag);
		Cancellation const* cancellation= m_cancellationRepository->Get(((Cancellation*)item.data)->GetCancelLocalId());
		Dealing* dealing = m_dealingRepository->Get(cancellation->GetOrderLocalId());
		dealing->OnCancelSuccess(0);
		m_business->OnDealing(*dealing);
		return dealing;
	}

	void OnTrade(Dealing* dealing,int quantity)
	{
		Trade trade(*dealing,dealing->GetOrderPrice(),quantity,dealing->GetSystemNo());
		dealing->OnTrade(trade);
		m_business->OnTrade(trade);
	}


	PendingMarket MinorSellOpenPendingMarket()
	{
		return PendingMarket(1,Direction::SELL,3000,10);
	}
	PendingMarket MinorSellStopPendingMarket()
	{
		return PendingMarket(1,Direction::SELL,2980,10);
	}
	PendingMarket MajorBuyOpenPendingMarket1()
	{
		return PendingMarket(0,Direction::BUY,3010,10);
	}
	PendingMarket MajorBuyOpenPendingMarket2()
	{
		return PendingMarket(0,Direction::BUY,3020,10);
	}
	PendingMarket MajorBuyOpenPendingMarket5()
	{
		return PendingMarket(0,Direction::BUY,3050,10);
	}


	PendingMarket MinorBuyOpenPendingMarket()
	{
		return PendingMarket(1,Direction::BUY,3000,10);
	}
	PendingMarket MinorBuyStopPendingMarket()
	{
		return PendingMarket(1,Direction::BUY,3020,10);
	}
	PendingMarket MajorSellOpenPendingMarket1()
	{
		return PendingMarket(0,Direction::SELL,2990,10);
	}
	PendingMarket MajorSellOpenPendingMarket5()
	{
		return PendingMarket(0,Direction::SELL,2950,10);
	}
};

TEST_F(OneLegArbitrageBusinessTest,NoMinorMarketNoChanceTest)/*
void OneLegArbitrageBusinessTest::foo() /**/
{
	OnCommand(Command::START_COMMAND);

	EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());

	m_business->OnPendingMarket(MajorBuyOpenPendingMarket1());
	EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());
	
	m_business->OnPendingMarket(MajorBuyOpenPendingMarket5());
	EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());
}


TEST_F(OneLegArbitrageBusinessTest,NoMarketTest)/*
void OneLegArbitrageBusinessTest::foo() /**/
{
	OnCommand(Command::START_COMMAND);

	ExpectSnapshot("start",Direction::BUY,0);

	m_business->OnPendingMarket(MinorSellOpenPendingMarket());

	m_business->OnPendingMarket(MajorBuyOpenPendingMarket1());
	EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());

	m_business->OnPendingMarket(MajorBuyOpenPendingMarket2());
	EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());
}

TEST_F(OneLegArbitrageBusinessTest,NoEnoughFundsTest)/*
void OneLegArbitrageBusinessTest::foo() /**/
{
	m_customer->Freeze((int)m_business.get(),m_customer->GetAvailable()-1);
	OnCommand(Command::START_COMMAND);

	ExpectSnapshot("start",Direction::BUY,0);

	m_business->OnPendingMarket(MinorSellOpenPendingMarket());

	m_business->OnPendingMarket(MajorBuyOpenPendingMarket1());
	EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());

	m_business->OnPendingMarket(MajorBuyOpenPendingMarket5());
	EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());
}

TEST_F(OneLegArbitrageBusinessTest,MinorOpenSentTest)/*
void OneLegArbitrageBusinessTest::foo() /**/
{
	OnCommand(Command::START_COMMAND);

	ExpectSnapshot("start",Direction::BUY,0);

	m_business->OnPendingMarket(MinorSellOpenPendingMarket());

	m_business->OnPendingMarket(MajorBuyOpenPendingMarket1());
	EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());

	m_business->OnPendingMarket(MajorBuyOpenPendingMarket5());
	ExpectSnapshot("minor open sent",Direction::BUY,0);
	ExpectOrder(1,Operation::OPEN,Direction::BUY,1,MinorSellOpenPendingMarket().price);
}


TEST_F(OneLegArbitrageBusinessTest,TooLateToMinorOpenSentTest)/*
void OneLegArbitrageBusinessTest::foo() /**/
{
	OnCommand(Command::START_COMMAND);

	ExpectSnapshot("start",Direction::BUY,0);

	m_business->OnPendingMarket(MinorSellOpenPendingMarket());

	m_business->OnPendingMarket(MajorBuyOpenPendingMarket1());
	EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());

	::Sleep(3000);
	m_business->OnPendingMarket(MajorBuyOpenPendingMarket5());
	EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());
}

TEST_F(OneLegArbitrageBusinessTest,MinorOpenCancellationSentTest)/*
void OneLegArbitrageBusinessTest::foo() /**/
{
	OnCommand(Command::START_COMMAND);

	ExpectSnapshot("start",Direction::BUY,0);

	m_business->OnPendingMarket(MinorSellOpenPendingMarket());

	m_business->OnPendingMarket(MajorBuyOpenPendingMarket1());
	EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());

	m_business->OnPendingMarket(MajorBuyOpenPendingMarket5());
	ExpectSnapshot("minor open sent",Direction::BUY,0);
	Dealing* minorOpenDealing = OnOrdered();
	ExpectSnapshot("minor open cancellation sent",Direction::BUY,0);
	ExpectCancellation(minorOpenDealing->GetLocalId());
}


TEST_F(OneLegArbitrageBusinessTest,MinorOpenCancellationSuccessTest)/*
void OneLegArbitrageBusinessTest::foo() /**/
{
	OnCommand(Command::START_COMMAND);

	ExpectSnapshot("start",Direction::BUY,0);

	m_business->OnPendingMarket(MinorSellOpenPendingMarket());

	m_business->OnPendingMarket(MajorBuyOpenPendingMarket1());
	EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());

	m_business->OnPendingMarket(MajorBuyOpenPendingMarket5());
	ExpectSnapshot("minor open sent",Direction::BUY,0);
	Dealing* minorOpenDealing = OnOrdered();
	ExpectSnapshot("minor open cancellation sent",Direction::BUY,0);
	OnCancellationSuccess();
	ExpectSnapshot("start",Direction::BUY,0);
}

TEST_F(OneLegArbitrageBusinessTest,MinorOpenTradeAndOffsetSentTest)/*
void OneLegArbitrageBusinessTest::foo() /**/
{
	OnCommand(Command::START_COMMAND);

	ExpectSnapshot("start",Direction::BUY,0);

	m_business->OnPendingMarket(MinorSellOpenPendingMarket());

	m_business->OnPendingMarket(MajorBuyOpenPendingMarket1());
	EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());

	m_business->OnPendingMarket(MajorBuyOpenPendingMarket5());
	ExpectSnapshot("minor open sent",Direction::BUY,0);
	Dealing* minorOpenDealing = OnOrdered();
	ExpectSnapshot("minor open cancellation sent",Direction::BUY,0);
	ExpectCancellation(minorOpenDealing->GetLocalId());
	OnTrade(minorOpenDealing,1);
	m_business->OnDealing(*minorOpenDealing);
	ExpectSnapshot("opened",Direction::BUY,1);
	ExpectOrder(1,Operation::OFFSET_TODAY,Direction::SELL,1,MinorSellOpenPendingMarket().price + 20);
}

TEST_F(OneLegArbitrageBusinessTest,MinorOpenTradeAndOffsetOrderedTest)/*
void OneLegArbitrageBusinessTest::foo() /**/
{
	OnCommand(Command::START_COMMAND);

	ExpectSnapshot("start",Direction::BUY,0);

	m_business->OnPendingMarket(MinorSellOpenPendingMarket());

	m_business->OnPendingMarket(MajorBuyOpenPendingMarket1());
	EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());

	m_business->OnPendingMarket(MajorBuyOpenPendingMarket5());
	ExpectSnapshot("minor open sent",Direction::BUY,0);
	Dealing* minorOpenDealing = OnOrdered();
	ExpectSnapshot("minor open cancellation sent",Direction::BUY,0);
	ExpectCancellation(minorOpenDealing->GetLocalId());
	OnTrade(minorOpenDealing,1);
	m_business->OnDealing(*minorOpenDealing);
	ExpectSnapshot("opened",Direction::BUY,1);
	OnOrdered();
	ExpectSnapshot("minor offset ordered",Direction::BUY,1);
}


TEST_F(OneLegArbitrageBusinessTest,MinorOffsetCompleteTest)/*
void OneLegArbitrageBusinessTest::foo() /**/
{
	OnCommand(Command::START_COMMAND);

	ExpectSnapshot("start",Direction::BUY,0);

	m_business->OnPendingMarket(MinorSellOpenPendingMarket());

	m_business->OnPendingMarket(MajorBuyOpenPendingMarket1());
	EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());

	m_business->OnPendingMarket(MajorBuyOpenPendingMarket5());
	ExpectSnapshot("minor open sent",Direction::BUY,0);
	Dealing* minorOpenDealing = OnOrdered();
	ExpectSnapshot("minor open cancellation sent",Direction::BUY,0);
	ExpectCancellation(minorOpenDealing->GetLocalId());
	OnTrade(minorOpenDealing,1);
	m_business->OnDealing(*minorOpenDealing);
	ExpectSnapshot("opened",Direction::BUY,1);
	Dealing* minorOffsetDealing = OnOrdered();
	ExpectSnapshot("minor offset ordered",Direction::BUY,1);
	OnTrade(minorOffsetDealing,1);
	m_business->OnDealing(*minorOffsetDealing);
	ExpectSnapshot("start",Direction::BUY,0);
}

TEST_F(OneLegArbitrageBusinessTest,StopMarketTest)/*
void OneLegArbitrageBusinessTest::foo() /**/
{
	OnCommand(Command::START_COMMAND);

	ExpectSnapshot("start",Direction::BUY,0);

	m_business->OnPendingMarket(MinorSellOpenPendingMarket());

	m_business->OnPendingMarket(MajorBuyOpenPendingMarket1());
	EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());

	m_business->OnPendingMarket(MajorBuyOpenPendingMarket5());
	ExpectSnapshot("minor open sent",Direction::BUY,0);
	Dealing* minorOpenDealing = OnOrdered();
	ExpectSnapshot("minor open cancellation sent",Direction::BUY,0);
	ExpectCancellation(minorOpenDealing->GetLocalId());
	OnTrade(minorOpenDealing,1);
	m_business->OnDealing(*minorOpenDealing);
	ExpectSnapshot("opened",Direction::BUY,1);
	Dealing* minorOffsetDealing = OnOrdered();
	ExpectSnapshot("minor offset ordered",Direction::BUY,1);

	m_business->OnPendingMarket(MinorSellStopPendingMarket());
	ExpectSnapshot("minor offset cancellation sent",Direction::BUY,1);
	OnCancellationSuccess();
	ExpectSnapshot("minor stop sent",Direction::BUY,1);
	Market const& market = m_marketStorage.GetMarket(m_business->GetArgument().GetMinor());
	ExpectOrder(1,Operation::OFFSET_TODAY,Direction::SELL,1,market.GetLowerLimit());
}


TEST_F(OneLegArbitrageBusinessTest,StopSuccessTest)/*
void OneLegArbitrageBusinessTest::foo() /**/
{
	OnCommand(Command::START_COMMAND);

	ExpectSnapshot("start",Direction::BUY,0);

	m_business->OnPendingMarket(MinorSellOpenPendingMarket());

	m_business->OnPendingMarket(MajorBuyOpenPendingMarket1());
	EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());

	m_business->OnPendingMarket(MajorBuyOpenPendingMarket5());
	ExpectSnapshot("minor open sent",Direction::BUY,0);
	Dealing* minorOpenDealing = OnOrdered();
	ExpectSnapshot("minor open cancellation sent",Direction::BUY,0);
	ExpectCancellation(minorOpenDealing->GetLocalId());
	OnTrade(minorOpenDealing,1);
	m_business->OnDealing(*minorOpenDealing);
	ExpectSnapshot("opened",Direction::BUY,1);
	Dealing* minorOffsetDealing = OnOrdered();
	ExpectSnapshot("minor offset ordered",Direction::BUY,1);

	m_business->OnPendingMarket(MinorSellStopPendingMarket());
	ExpectSnapshot("minor offset cancellation sent",Direction::BUY,1);
	OnCancellationSuccess();
	ExpectSnapshot("minor stop sent",Direction::BUY,1);
	Dealing* minorStopDealing = OnOrdered();
	OnTrade(minorStopDealing,1);
	m_business->OnDealing(*minorStopDealing);
	ExpectSnapshot("start",Direction::BUY,0);
}

TEST_F(OneLegArbitrageBusinessTest,MinorSellOpenSentTest)/*
void OneLegArbitrageBusinessTest::foo() /**/
{
	OnCommand(Command::START_COMMAND);

	ExpectSnapshot("start",Direction::BUY,0);

	m_business->OnPendingMarket(MinorBuyOpenPendingMarket());

	m_business->OnPendingMarket(MajorSellOpenPendingMarket1());
	EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());

	m_business->OnPendingMarket(MajorSellOpenPendingMarket5());
	ExpectSnapshot("minor open sent",Direction::SELL,0);
	ExpectOrder(1,Operation::OPEN,Direction::SELL,1,MinorBuyOpenPendingMarket().price);
}

TEST_F(OneLegArbitrageBusinessTest,MinorSellOpenTradeAndOffsetSentTest)/*
void OneLegArbitrageBusinessTest::foo() /**/
{
	OnCommand(Command::START_COMMAND);

	ExpectSnapshot("start",Direction::BUY,0);

	m_business->OnPendingMarket(MinorBuyOpenPendingMarket());

	m_business->OnPendingMarket(MajorSellOpenPendingMarket1());
	EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());

	m_business->OnPendingMarket(MajorSellOpenPendingMarket5());
	ExpectSnapshot("minor open sent",Direction::SELL,0);
	Dealing* minorOpenDealing = OnOrdered();
	ExpectSnapshot("minor open cancellation sent",Direction::SELL,0);
	ExpectCancellation(minorOpenDealing->GetLocalId());
	OnTrade(minorOpenDealing,1);
	m_business->OnDealing(*minorOpenDealing);
	ExpectSnapshot("opened",Direction::SELL,1);
	ExpectOrder(1,Operation::OFFSET_TODAY,Direction::BUY,1,MinorBuyOpenPendingMarket().price - 20);
}

TEST_F(OneLegArbitrageBusinessTest,SellOpenAllTest)/*
void OneLegArbitrageBusinessTest::foo() /**/
{
	OnCommand(Command::START_COMMAND);

	ExpectSnapshot("start",Direction::BUY,0);

	m_business->OnPendingMarket(MinorBuyOpenPendingMarket());

	m_business->OnPendingMarket(MajorSellOpenPendingMarket1());
	EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());

	m_business->OnPendingMarket(MajorSellOpenPendingMarket5());
	ExpectSnapshot("minor open sent",Direction::SELL,0);
	Dealing* minorOpenDealing = OnOrdered();
	ExpectSnapshot("minor open cancellation sent",Direction::SELL,0);
	ExpectCancellation(minorOpenDealing->GetLocalId());
	OnTrade(minorOpenDealing,1);
	m_business->OnDealing(*minorOpenDealing);
	ExpectSnapshot("opened",Direction::SELL,1);
	Dealing* minorOffsetDealing = OnOrdered();
	ExpectSnapshot("minor offset ordered",Direction::SELL,1);

	m_business->OnPendingMarket(MinorBuyStopPendingMarket());
	ExpectSnapshot("minor offset cancellation sent",Direction::SELL,1);
	OnCancellationSuccess();
	ExpectSnapshot("minor stop sent",Direction::SELL,1);
	Dealing* minorStopDealing = OnOrdered();
	OnTrade(minorStopDealing,1);
	m_business->OnDealing(*minorStopDealing);
	ExpectSnapshot("start",Direction::BUY,0);
}